iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
Software Development

從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰系列 第 19

Day 19 - 軟體重插拔 (Software Re-plug):不碰硬體,用指令強制 Windows 重新掛載

  • 分享至 

  • xImage
  •  

在上一篇文章中,我們探討了 Windows 積極的緩存機制如何導致剛寫入隨身碟的資料,在未經安全移除的情況下被遺失。為了解決這個問題,除了確保底層的資料同步(使用 fsync 甚至直接 flush block device),我們還面臨一個更棘手的 UX(使用者體驗)問題:如何讓 Windows 知道檔案系統已經更新了?

[問題情境] Windows 的「視而不見」

想像一下這個情境:

  1. EdgeNode (我們的邊緣運算閘道器) 透過 USB 線連接到 Windows 電腦。
  2. Windows 將其識別為一個隨身碟 (D 槽),並讀取了裡面的 FAT32 檔案系統。
  3. 此時,EdgeNode 透過內部的 UART 介面收到了一筆新的生理特徵量測資料。
  4. EdgeNode 暫時卸載 (Unmount) 隨身碟,將新資料寫入底層的 .bin 映像檔,然後重新掛載。
  5. 使用者在 Windows 打開 D 槽,發現... 什麼都沒變! 沒有新檔案!

為什麼會這樣?因為 Windows 的 USB 大量儲存驅動程式 (Mass Storage Driver) 非常依賴初始掛載時的快取。除非 Windows 偵測到硬體發生了「拔出」再「插入」的動作,否則它不會重新掃描檔案配置表 (FAT)。

難道我們要要求護理人員每次量測完,都要手動去拔掉再插上那根 USB 線嗎?這絕對會被客訴到爆。

[錯誤嘗試] 試圖用腳本重整檔案總管

起初,我們試圖在 Windows 端寫一支小程式,透過 Windows API 去觸發磁碟重新整理,甚至嘗試送出 IOCTL_DISK_UPDATE_PROPERTIES。但這不僅需要額外在 PC 端安裝軟體,還常常因為權限不足而失敗。我們的目標是打造一個真正的「隨插即用」無頭設備 (Headless Device),不應該依賴 PC 端的任何客製化軟體。

[底層原理] USB 狀態機與 ConfigFS 的魔法

回到 EdgeNode (Raspberry Pi) 的 Linux 底層。我們是透過 ConfigFS 來模擬 USB 隨身碟的。在 Linux USB Gadget 驅動的設計中,虛擬設備的生命週期與 UDC (USB Device Controller) 緊密綁定。

當我們把設定好的 Gadget 名稱寫入 UDC 檔案時,Linux 核心就會在實體的 USB 介面上觸發一個硬體級別的電位變化(Pull-up resistor 改變),告訴主機端(Windows):「嗨!有一個新設備插進來囉!」

相反地,如果我們把一個空字串寫入 UDC 檔案,Linux 就會解除電位,主機端就會以為設備被「拔出」了。

這就是所謂的 軟體重插拔 (Software Re-plug)

[最終解決方案] 強制 Windows 重新掛載

掌握了這個原理,我們的解決方案就變得異常優雅且完全不需要依賴硬體動作。

當 EdgeNode 內部寫入新資料後,我們只需執行以下腳本:

#!/bin/bash
# software_replug.sh

GADGET_DIR="/sys/kernel/config/usb_gadget/edge_node"
UDC_FILE="$GADGET_DIR/UDC"

# 1. 取得當前的 UDC 名稱 (例如 20980000.usb 或 fe980000.usb)
CURRENT_UDC=$(ls /sys/class/udc | head -n 1)

# 2. 模擬拔出 (Unbind)
echo "拔出虛擬 USB 設備..."
echo "" > "$UDC_FILE"

# 等待一下,讓 Windows 確實反應設備已移除
sleep 1

# 3. 模擬插入 (Bind)
echo "插入虛擬 USB 設備..."
echo "$CURRENT_UDC" > "$UDC_FILE"

[!TIP]
關鍵細節:為何要 sleep 1
如果拔出和插入的間隔太短,Windows 的 USB 驅動可能會把這個短暫的斷線視為電氣雜訊 (Glitch) 而忽略它。給予大約 1 秒的緩衝,能確保 Windows 確實觸發了 Device Removal 事件,並清除該磁碟的緩存。

實際運作流程

結合我們前幾天的知識,EdgeNode 處理新資料的完整生命週期變為:

  1. 攔截 (Intercept):監聽 PC 端是否沒有在使用檔案。
  2. 切斷 (Disconnect):將 USB 卸載,確保 PC 不能亂動資料。
  3. 寫入 (Write):後台 Python 程式將熱騰騰的感測器資料寫入 .bin 映像檔,並強制 sync
  4. 重插拔 (Re-plug):執行上述的 UDC Unbind / Bind。
  5. 重生 (Respawn):Windows 偵測到新設備,自動彈出視窗,使用者看到熱騰騰的新檔案!

透過這招「軟體重插拔」,我們成功在不修改任何硬體線路、不增加任何實體按鈕的情況下,完美解決了檔案系統更新不同步的世紀難題。

這就是軟硬整合的浪漫:用兩行指令,改變真實世界的物理行為。

明天,我們將跨入一個全新的領域:當系統越來越複雜,我們該如何控制 EdgeNode 上那顆至關重要的 RGB 指示燈?敬請期待 Day 20:多執行緒的混亂!


上一篇
Day 18:邊緣設備的高頻同步實戰—從 Race Condition 到二補數對齊
下一篇
Day 20 - 多執行緒的混亂:為何 Linux 內建的 CPU 排程器不適合用來控制 LED 燈號?
系列文
從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言